package svc

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
	"time"
	"yunzhan/common/models"
	"yunzhan/common/utils"
	"yunzhan/rpc-server/internal/config"
)

type ServiceContext struct {
	Config               config.Config
	Conn                 sqlx.SqlConn
	monitorCancel        context.CancelFunc
	monitorWg            sync.WaitGroup
	httpClient           *http.Client
	ComponentInfoManager *models.ComponentInfoManager
}

func NewServiceContext(c config.Config) *ServiceContext {
	mysqlConn := sqlx.NewMysql(c.Mysql.DataSource)
	svcCtx := &ServiceContext{
		Config:     c,
		Conn:       mysqlConn,
		httpClient: &http.Client{Timeout: 10 * time.Second},
	}

	// 初始化 componentInfoManager
	flushInterval := 5 * time.Second
	maxBatchSize := 100
	retryDelay := 2 * time.Second
	maxRetries := 3
	apiURL := fmt.Sprintf("http://%s:%d", c.RestServices["apiServer"].RestConf.Host, c.RestServices["apiServer"].RestConf.Port)

	svcCtx.ComponentInfoManager = models.NewComponentInfoManager(1000, apiURL, flushInterval, maxBatchSize, retryDelay, maxRetries)
	svcCtx.startMonitorComponents()
	return svcCtx
}

func (svc *ServiceContext) Start() {
	svc.startMonitorComponents()
}

func (svc *ServiceContext) Stop() {
	svc.stopMonitorComponents()
	svc.ComponentInfoManager.Close()
}

func (svc *ServiceContext) startMonitorComponents() {
	ctx, cancel := context.WithCancel(context.Background())
	svc.monitorCancel = cancel

	go func() {
		ticker := time.NewTicker(10 * time.Second)
		defer ticker.Stop()
		for {
			select {
			case <-ctx.Done():
				logx.Infof("监控线程已停止")
				return
			case <-ticker.C:
				svc.monitorWg.Add(1)
				go svc.queryAndMonitorComponents()
			}
		}
	}()
}

func (svc *ServiceContext) stopMonitorComponents() {
	if svc.monitorCancel != nil {
		svc.monitorCancel()
	}
	svc.monitorWg.Wait()
}

func (svc *ServiceContext) queryAndMonitorComponents() {
	defer svc.monitorWg.Done()

	components := svc.queryDeployedComponents()
	if len(components) == 0 {
		logx.Infof("当前节点未部署任何组件服务...")
		return
	}

	var wg sync.WaitGroup
	for _, component := range components {
		wg.Add(1)
		go func(comp models.ComponentInfo) {
			defer wg.Done()
			svc.monitorComponentProcess(&comp)
		}(component)
	}
	wg.Wait()
}

type QueryComponentInfoResponse struct {
	Code           int                    `json:"code"`
	Message        string                 `json:"message"`
	ComponentInfos []models.ComponentInfo `json:"componentInfos"`
}

func (svc *ServiceContext) queryDeployedComponents() []models.ComponentInfo {
	var components []models.ComponentInfo

	currentInternalIP, err := utils.GetCurrentInternalIP()
	if err != nil {
		logx.Errorf("无法获取当前主机IP: %v", err)
		return components
	}

	currentHostname, err := utils.GetCurrentHostname()
	if err != nil {
		logx.Errorf("无法获取当前主机名: %v", err)
		return components
	}

	// 获取可执行文件的路径
	exePath, err := os.Executable()
	// 获取可执行文件所在的上一级目录
	parentDir := filepath.Dir(filepath.Dir(exePath))

	// 构造tmp目录路径
	tmpDir := filepath.Join(parentDir, "tmp")

	// 构造CLUSTER文件的路径
	clusterFilePath := filepath.Join(tmpDir, "CLUSTER")

	// 读取CLUSTER文件内容
	clusterID, err := models.ReadClusterID(clusterFilePath)
	queryParams := url.Values{}
	queryParams.Set("clusterID", clusterID)
	queryParams.Set("nodeIP", currentInternalIP)
	queryParams.Set("nodeHost", currentHostname)

	url := fmt.Sprintf("http://%s:%d/v1/log/query_component?%s",
		svc.Config.RestServices["apiServer"].RestConf.Host,
		svc.Config.RestServices["apiServer"].RestConf.Port,
		queryParams.Encode())

	httpReq, err := http.NewRequest("GET", url, nil)
	if err != nil {
		logx.Errorf("无法创建HTTP请求: %v", err)
		return components
	}

	httpResp, err := svc.httpClient.Do(httpReq)
	if err != nil {
		logx.Errorf("发送HTTP请求失败: %v", err)
		return components
	}
	defer httpResp.Body.Close()

	if httpResp.StatusCode != http.StatusOK {
		logx.Errorf("HTTP响应状态码错误: %v", httpResp.StatusCode)
		return components
	}

	var resp QueryComponentInfoResponse
	err = json.NewDecoder(httpResp.Body).Decode(&resp)
	if err != nil {
		logx.Errorf("无法解析HTTP响应: %v", err)
		return components
	}

	if resp.Code != 200 || len(resp.ComponentInfos) == 0 {
		return components
	}

	for _, component := range resp.ComponentInfos {
		if component.ComponentName != "JDK" {
			components = append(components, component)
		}
	}

	return components
}

func (svc *ServiceContext) monitorComponentProcess(component *models.ComponentInfo) {
	status := checkComponentStatus(component)
	if !status {
		logx.Errorf("%s %s进程未运行", component.ComponentName, component.ComponentRole)
		component.Status = false
	} else {
		logx.Infof("%s %s进程正在运行", component.ComponentName, component.ComponentRole)
		component.Status = true
	}

	svc.ComponentInfoManager.SendComponentInfo(component)
}

func checkComponentStatus(component *models.ComponentInfo) bool {
	checkCommands := map[string]string{
		"elasticsearch:server":         "pgrep -f elasticsearch && exec bash",
		"redis:server":                 "pgrep -f redis-server && exec bash",
		"redis:sentinel":               "pgrep -f redis-sentinel && exec bash",
		"nginx:server":                 "pgrep -f nginx && exec bash",
		"keepalived:server":            "pgrep -f keepalived && exec bash",
		"kafka:broker":                 "pgrep -f Kafka && exec bash",
		"kafka-exporter:server":        "pgrep -f kafka_exporter && exec bash",
		"prometheus:server":            "pgrep -f prometheus && exec bash",
		"grafana:server":               "pgrep -f grafana && exec bash",
		"alertmanager:server":          "pgrep -f alertmanager && exec bash",
		"zookeeper:leader":             "pgrep -f QuorumPeerMain && exec bash",
		"zookeeper:follower":           "pgrep -f QuorumPeerMain && exec bash",
		"hbase:hmaster":                "pgrep -f HMaster && exec bash",
		"hbase:hregionserver":          "pgrep -f HRegionServer && exec bash",
		"minio:server":                 "pgrep -f minio && exec bash",
		"hdfs:namenode":                "pgrep -f NameNode && exec bash",
		"hdfs:datanode":                "pgrep -f DataNode && exec bash",
		"hdfs:journalnode":             "pgrep -f JournalNode && exec bash",
		"hive:hiveserver2":             "pgrep -f hiveserver2 && exec bash",
		"hive:metastore":               "pgrep -f Metastore && exec bash",
		"hdfs:dfszkfailovercontroller": "pgrep -f DFSZKFailoverController && exec bash",
		"yarn:resourcemanager":         "pgrep -f ResourceManager && exec bash",
		"yarn:nodemanager":             "pgrep -f NodeManager && exec bash",
		"yarn:jobhistoryserver":        "pgrep -f JobHistoryServer && exec bash",
	}

	key := strings.ToLower(component.ComponentName) + ":" + strings.ToLower(component.ComponentRole)

	if strings.ToLower(component.ComponentName) == "redis" && !(strings.ToLower(component.ComponentRole) == "server" || strings.ToLower(component.ComponentRole) == "sentinel") {

		// 优化正则表达式，避免回溯
		pattern := `require_pass=([^,\s]+)`
		re := regexp.MustCompile(pattern)
		match := re.FindStringSubmatch(component.AdditionalInfo)

		if len(match) > 1 {
			// 解密逻辑...
		} else {
			logx.Errorf("require_pass not found")
			return false
		}
	}

	checkCommand, exists := checkCommands[key]
	if !exists {
		logx.Errorf("未找到 %s 的检查命令", key)
		return false
	}

	output, err := utils.ExecCommand(checkCommand)
	if err != nil || strings.TrimSpace(output) == "" {
		logx.Errorf("%s 进程未运行: %v", component.ComponentName, err)
		return false
	}

	return true
}
